package com.spiro;

import com.spiro.common.BaseJavaClient;
import com.spiro.common.BaseJavaServer;
import com.spiro.common.tutorial.Calculator;
import com.spiro.normal.bio.BioClient;
import com.spiro.normal.bio.BioServer;
import com.spiro.normal.bio.MultiThreadBioServer;
import com.spiro.normal.nio.MultiThreadNioServer;
import com.spiro.normal.nio.NioClient;
import com.spiro.normal.nio.NioServer;
import com.spiro.ssl.MultiThreadSslBioServer;
import com.spiro.ssl.SslBioClient;
import com.spiro.ssl.SslBioServer;
import org.apache.commons.cli.*;
import org.apache.thrift.TException;

import java.util.List;

// Generated code

public class TestThriftClientMain {

    public static final String IO_MODEL_BIO = "BIO";
    public static final String IO_MODEL_NIO = "NIO";

    public static void main(String[] args) {

        Options options = new Options();
        options.addOption("i", "io", true, "[required] I/O model: 'BIO' or 'NIO'");
        options.addOption("s", "ssl", false, "TCP SSL");
        options.addOption("o", "host", true, "[required] Server host");
        options.addOption("p", "port", true, "[required] Server port");
        options.addOption("n", "num", true, "Client num");
        options.addOption("c", "count", true, "Execute count");
        options.addOption("h", "help", false, "Help information");

        CommandLineParser parser = new DefaultParser();

        String ioModel = null;
        boolean isSSL = false;
        String portStr = null;
        String host = null;
        int num = 1;
        int count = 1;

        try {
            CommandLine cmd = parser.parse( options, args);
            if (cmd.hasOption("help")) {
                printHelp(options);
                System.exit(0);
            }

            if (cmd.hasOption("io")) {
                ioModel = cmd.getOptionValue("io");
            }

            if (cmd.hasOption("ssl")) {
                isSSL = true;
            }

            if (cmd.hasOption("host")) {
                host = cmd.getOptionValue("host");
            }

            if (cmd.hasOption("port")) {
                portStr = cmd.getOptionValue("port");
            }

            if (cmd.hasOption("num")) {
                num = Integer.valueOf(cmd.getOptionValue("num"));
            }

            if (cmd.hasOption("count")) {
                count = Integer.valueOf(cmd.getOptionValue("count"));
            }

        } catch (ParseException e) {
            e.printStackTrace();
            System.exit(1);
        }

        if (ioModel == null) {
            System.out.println("io is null.");
            printHelp(options);
            System.exit(1);
        }

        if (portStr == null) {
            System.out.println("port is null.");
            printHelp(options);
            System.exit(1);
        }

        int port = Integer.valueOf(portStr);

        List<? extends BaseJavaClient> clients = null;

        if (isSSL) {
            if (IO_MODEL_BIO.equals(ioModel)) {
                clients = SslBioClient.getInstances(num, host, port);
            } else {
                System.out.println("SSL must match with BIO.");
                System.exit(1);
            }
        } else {
            if (IO_MODEL_BIO.equals(ioModel)) {

                clients = BioClient.getInstances(num, host, port);

            } else if (IO_MODEL_NIO.equals(ioModel)) {

                clients = NioClient.getInstances(num, host, port);

            } else {
                System.out.println("Invalid argument <io>");
                System.exit(1);
            }
        }

        int i = 0;
        for (BaseJavaClient client : clients) {
            i++;
            Thread t = new Thread(new CalculatorTestRunnable(client, count), "client-" + i);
            t.start();
            System.out.println("client.impl=" + client.getClass().getName()
                    + ", name=client-" + i + ", started.");
        }

    }

    public static class CalculatorTestRunnable implements Runnable {

        private final BaseJavaClient client;
        private final int executeTimes;

        public CalculatorTestRunnable(BaseJavaClient client, int executeTimes) {
            this.client = client;
            this.executeTimes = executeTimes;
        }

        @Override
        public void run() {

            int count = 0;

            try {
                Calculator.Client _client = client.connectAndGet();

                long start = System.currentTimeMillis();
                while (true) {

                    _client.add(1, 2);

                    count++;
                    if (count == this.executeTimes) {
                        break;
                    }
                }
                long end = System.currentTimeMillis();

                System.out.println("client.impl=" + this.client.getClass().getName()
                        + ", executeTimes=" + this.executeTimes + ", take " + (end - start) + " ms.");

            } catch (TException e) {
                e.printStackTrace();
            } finally {
                client.close();
            }

        }
    }


    public static void printHelp(Options options) {

        // automatically generate the help statement
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp( "Main", options );
    }

}
